﻿
namespace Graph.Algorithm.Core
{
    public static class ConvertService
    { 

        /// <summary>
        /// 将十进制的32位整型数转换为32位二进制字符串
        /// </summary>
        /// <param name="i"></param>
        /// <returns></returns>
        public static bool Int32ToBinary(this int i, out string v)
        {
            try
            {
                v = Convert.ToString(i, 2).PadLeft(32, '0');
                return true;
            }
            catch (Exception)
            {
                v = default;
                return false;
            }
        }
         
        /// <summary>
        /// 将十进制的32位单精度浮点数转换为32位二进制字符串
        /// </summary>
        /// <param name="i"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        public static bool Float32ToBinary(this float i, out string v)
        {
            try
            {
                float j = i;
                i = Math.Abs(i);
                int i_left = Convert.ToInt32(Math.Floor(i));//获取整数部分
                float i_right = i - i_left;//获取小数部分
                Int32ToBinary(i_left, out string left);//整数部分转换为二进制
                string right = "";
                while (i_right != 1)//小数部分转换为二进制
                {
                    float temp = i_right * 2;
                    right += temp >= 1 ? "1" : "0";
                    if (temp == 1 || temp == 0)
                    {
                        break;
                    }
                    i_right = temp > 1 ? temp - 1 : temp;
                }
                string S = j > 0 ? "0" : "1";//获取符号位的二进制
                if (!left.Contains("1"))
                {
                    int e = 127 - (right.IndexOf('1') + 1);//获取指数位的十进制
                    Int32ToBinary(e, out string E);//获取指数位的二进制
                    string M = right.Substring(right.IndexOf('1') + 1);
                    if (M.Length > 23)
                    {
                        M = M.Substring(0, 23);
                    }
                    else if (M.Length < 23)
                    {
                        M = M.PadRight(23, '0');
                    }
                    v = S + E.Substring(E.Length - 8) + M;
                }
                else
                {
                    int e = left.Length - left.IndexOf('1') - 1 + 127;//获取指数位的十进制
                    Int32ToBinary(e, out string E);//获取指数位的二进制
                    var z = (left.IndexOf('1') + 1);//获取最高正数位
                    string M = ((z >= left.Length ? "" : left.Substring(z)) + right);//获取尾数
                    if (M.Length > 23)
                    {
                        M = M.Substring(0, 23);
                    }
                    else if (M.Length < 23)
                    {
                        M = M.PadRight(23, '0');
                    }
                    v = S + E.Substring(E.Length - 8) + M;
                }
                return true;
            }
            catch (Exception)
            {
                v = default;
                return false;
            }
        }

        /// <summary>
        /// 将32位二进制字符串转换为十进制的单精度浮点数
        /// </summary>
        /// <param name="i"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        public static bool BinaryToFloat32(this string i, out float v)
        {
            try
            {
                var s = i.Substring(0, 1);//获取符号位字符串
                var e = i.Substring(1, 8);//获取指数位字符串
                var m = i.Substring(9);//获取尾数字符串
                BinaryToInt32(s, out int S);//把符号转换成十进制
                BinaryToInt32(e, out int E);//获取指数转换成十进制
                var m_left = $"1{m.Substring(0, E - 127)}";//获取整数部分二进制字符串
                var m_right = m.Substring(E - 127);//获取小数部分二进制字符串
                BinaryToInt32(m_left, out int left);//把整数部分转换为十进制
                var right = 0f;
                for (int index = 0; index < m_right.Length; index++)//把小数部分转换为十进制
                {
                    var temp_value = Convert.ToSingle(m_right[index].ToString());
                    var temp_index = Convert.ToSingle(Math.Pow(2, -(index + 1)));
                    right += (temp_value * temp_index);
                }
                v = left + right;//合并整数部分和小数部分
                v = S == 1 ? -v : v;//添加符号
                return true;
            }
            catch
            {
                v = default;
                return false;
            }
        }

        /// <summary>
        /// 将32位二进制字符串转换为十进制的32位整型数
        /// </summary>
        /// <param name="i"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        public static bool BinaryToInt32(this string i, out int v)
        {
            try
            {
                v = Convert.ToInt32(i, 2);
                return true;
            }
            catch
            {
                v = default;
                return false;
            }
        }



        #region dfe


        /// <summary>
        /// 32位二进制转化为对应的浮点数float【Real】
        /// </summary>
        /// <param name="binaryArraySource"></param>
        /// <returns></returns>
        static float Binary32BitToFloat(byte[] binaryArraySource)
        {
            if (binaryArraySource == null || binaryArraySource.Length != 4)
            {
                throw new ArgumentException($"源数组不能为空并且有且只有4个元素", nameof(binaryArraySource));
            }
            byte[] binaryArray = binaryArraySource.Reverse().ToArray();
            Console.WriteLine($"将数组顺序反转，反转后为【{string.Join(",", binaryArray)}】");
            IEnumerable<string> binaryCollection = binaryArray.Select(element => Convert.ToString(element, 2).PadLeft(8, '0'));
            string binaryString = string.Join("", binaryCollection);
            Console.WriteLine($"转化为32位二进制，为【{string.Join("\x20", binaryCollection)}】");
            string signString = (binaryString[0] == '1' ? "-" : "+");
            Console.WriteLine($"符号位占用1位，为【{signString}】");
            string exponent = binaryString.Substring(1, 8);
            int shiftCount = Convert.ToInt32(exponent, 2) - 127;
            Console.WriteLine($"指数位为8位【{exponent}】,对应数字【{Convert.ToInt32(exponent, 2)}】，共移动【{shiftCount}】位");
            string mantissa = binaryString.Substring(9);
            string dotString = $"1.{mantissa}";
            Console.WriteLine($"尾数位为23位【{mantissa}】,尾数位前面添加一个1并插入移位小数点,字符串为【{dotString}乘以2的{shiftCount}次方】");
            dotString = dotString.Replace(".", "").Insert(shiftCount + 1, ".");
            Console.WriteLine($"即【{dotString}】");
            string integerPart = dotString.Substring(0, shiftCount + 1);//整数部分
            string fractionalPart = dotString.Substring(shiftCount + 2);//小数部分

            //整数部分：从低位到高位 依次是2的0次方，2个1次方，2的2次方，然后累加
            long numberInteger = 0;
            for (int i = 0; i < integerPart.Length; i++)
            {
                if (integerPart[i] == '1')
                {
                    numberInteger += (1L << (integerPart.Length - 1 - i));
                }
            }
            //小数部分：从小数点开始分别是2的-1次幂、-2次幂、-3次幂……
            decimal numberFractional = 0M;
            for (int i = 0; i < fractionalPart.Length; i++)
            {
                if (fractionalPart[i] == '1')
                {
                    numberFractional += (decimal)Math.Pow(2, -1 - i);
                }
            }
            Console.WriteLine($"整数部分【{integerPart}】,对应整数为【{numberInteger}】.或者使用Convert，整数也为【{Convert.ToInt32(integerPart, 2)}】");
            Console.WriteLine($"小数部分【{fractionalPart}】,对应小数【{numberFractional}】");
            string destNumber = $"{signString}{numberInteger + numberFractional}";
            Console.WriteLine($"32位二进制对应的浮点数为【{destNumber}】,使用BitConverter转换为浮点数的结果为【{BitConverter.ToSingle(binaryArraySource, 0)}】");
            return float.Parse(destNumber);
        }

        /// <summary>
        /// 64位二进制转化为对应的双精度浮点数double【Double】
        /// </summary>
        /// <param name="binaryArraySource"></param>
        /// <returns></returns>
        static double Binary64BitToDouble(byte[] binaryArraySource)
        {
            if (binaryArraySource == null || binaryArraySource.Length != 8)
            {
                throw new ArgumentException($"源数组不能为空并且有且只有8个元素", nameof(binaryArraySource));
            }
            byte[] binaryArray = binaryArraySource.Reverse().ToArray();
            Console.WriteLine($"将数组顺序反转，反转后为【{string.Join(",", binaryArray)}】");
            IEnumerable<string> binaryCollection = binaryArray.Select(element => Convert.ToString(element, 2).PadLeft(8, '0'));
            string binaryString = string.Join("", binaryCollection);
            Console.WriteLine($"转化为64位二进制，为【{string.Join("\x20", binaryCollection)}】");
            string signString = (binaryString[0] == '1' ? "-" : "+");
            Console.WriteLine($"符号位占用1位，为【{signString}】");
            string exponent = binaryString.Substring(1, 11);
            int shiftCount = Convert.ToInt32(exponent, 2) - 1023;
            Console.WriteLine($"指数位为8位【{exponent}】,对应数字【{Convert.ToInt32(exponent, 2)}】，共移动【{shiftCount}】位");
            string mantissa = binaryString.Substring(12);
            string dotString = $"1.{mantissa}";
            Console.WriteLine($"尾数位为52位【{mantissa}】,尾数位前面添加一个1并插入移位小数点,字符串为【{dotString}乘以2的{shiftCount}次方】");
            dotString = dotString.Replace(".", "").Insert(shiftCount + 1, ".");
            Console.WriteLine($"即【{dotString}】");
            string integerPart = dotString.Substring(0, shiftCount + 1);//整数部分
            string fractionalPart = dotString.Substring(shiftCount + 2);//小数部分

            //整数部分：从低位到高位 依次是2的0次方，2个1次方，2的2次方，然后累加
            long numberInteger = 0L;
            for (int i = 0; i < integerPart.Length; i++)
            {
                if (integerPart[i] == '1')
                {
                    numberInteger += (1L << (integerPart.Length - 1 - i));
                }
            }
            //小数部分：从小数点开始分别是2的-1次幂、-2次幂、-3次幂……
            decimal numberFractional = 0M;
            for (int i = 0; i < fractionalPart.Length; i++)
            {
                if (fractionalPart[i] == '1')
                {
                    numberFractional += (decimal)Math.Pow(2, -1 - i);
                }
            }
            Console.WriteLine($"整数部分【{integerPart}】,对应整数为【{numberInteger}】.或者使用Convert，整数也为【{Convert.ToInt64(integerPart, 2)}】");
            Console.WriteLine($"小数部分【{fractionalPart}】,对应小数【{numberFractional}】");
            string destNumber = $"{signString}{numberInteger + numberFractional}";
            Console.WriteLine($"64位二进制对应的浮点数为【{destNumber}】,使用BitConverter转换为浮点数的结果为【{BitConverter.ToDouble(binaryArraySource, 0)}】");
            return double.Parse(destNumber);
        }

        /// <summary>
        /// 通用的二进制32位或64位 转浮点小数
        /// </summary>
        /// <typeparam name="T">仅支持float和double</typeparam>
        /// <param name="binaryArraySource"></param>
        /// <returns></returns>
        static T BinaryBitToFractional<T>(byte[] binaryArraySource) where T : struct
        {
            if (typeof(T) != typeof(float) && typeof(T) != typeof(double))
            {
                throw new Exception($"类型错误，必须是浮点数类型【float或double】");
            }
            if (binaryArraySource == null)
            {
                throw new ArgumentException($"源数组不能为空", nameof(binaryArraySource));
            }
            if (typeof(T) == typeof(float) && binaryArraySource.Length != 4)
            {
                throw new ArgumentException($"转化为float时，源数组必须有且只有4个元素", nameof(binaryArraySource));
            }
            if (typeof(T) == typeof(double) && binaryArraySource.Length != 8)
            {
                throw new ArgumentException($"转化为double时，源数组必须有且只有8个元素", nameof(binaryArraySource));
            }

            //单精度float:N共32位，其中S占1位，E占8位，M占23位。因此小数点后最多精确到23/4=6位 
            int signBitCount = 1;//符号位数,代表正数还是负数
            int exponentBitCount = 8;//指数位数
            int mantissaBitCount = 23;//尾数位数
            int totalBitCount = 32;//二进制总位数
            if (typeof(T) == typeof(double))
            {
                //双精度double:N共64位，其中S占1位，E占11位，M占52位。因此小数点后最多精确到52/4=13位 
                exponentBitCount = 11;//指数位数
                mantissaBitCount = 52;//尾数位数
                totalBitCount = 64;//二进制总位数
            }
            byte[] binaryArray = binaryArraySource.Reverse().ToArray();
            Console.WriteLine($"将数组顺序反转，反转后为【{string.Join(",", binaryArray)}】");
            IEnumerable<string> binaryCollection = binaryArray.Select(element => Convert.ToString(element, 2).PadLeft(8, '0'));
            string binaryString = string.Join("", binaryCollection);
            Console.WriteLine($"转化为【{totalBitCount}】位二进制，为【{string.Join("\x20", binaryCollection)}】");
            string signString = (binaryString[0] == '1' ? "-" : "+");
            Console.WriteLine($"符号位占用【{signBitCount}】位，为【{signString}】");
            string exponent = binaryString.Substring(1, exponentBitCount);
            int shiftCount = Convert.ToInt32(exponent, 2) - (1 << (exponentBitCount - 1)) + 1;
            Console.WriteLine($"指数位为【{exponentBitCount}】位【{exponent}】,对应数字【{Convert.ToInt32(exponent, 2)}】，共移动【{shiftCount}】位");
            string mantissa = binaryString.Substring(signBitCount + exponentBitCount);
            string dotString = $"1.{mantissa}";
            Console.WriteLine($"尾数位为【{mantissaBitCount}】位【{mantissa}】,尾数位前面添加一个1并插入移位小数点,字符串为【{dotString}乘以2的{shiftCount}次方】");
            dotString = dotString.Replace(".", "").Insert(shiftCount + 1, ".");
            Console.WriteLine($"即【{dotString}】");
            string integerPart = dotString.Substring(0, shiftCount + 1);//整数部分
            string fractionalPart = dotString.Substring(shiftCount + 2);//小数部分

            //整数部分：从低位到高位 依次是2的0次方，2个1次方，2的2次方，然后累加
            long numberInteger = 0L;
            for (int i = 0; i < integerPart.Length; i++)
            {
                if (integerPart[i] == '1')
                {
                    numberInteger += (1L << (integerPart.Length - 1 - i));
                }
            }
            //小数部分：从小数点开始分别是2的-1次幂、-2次幂、-3次幂……
            decimal numberFractional = 0M;
            for (int i = 0; i < fractionalPart.Length; i++)
            {
                if (fractionalPart[i] == '1')
                {
                    numberFractional += (decimal)Math.Pow(2, -1 - i);
                }
            }
            Console.WriteLine($"整数部分【{integerPart}】,对应整数为【{numberInteger}】.或者使用Convert，整数也为【{Convert.ToInt64(integerPart, 2)}】");
            Console.WriteLine($"小数部分【{fractionalPart}】,对应小数【{numberFractional}】");
            string destNumber = $"{signString}{numberInteger + numberFractional}";
            if (typeof(T) == typeof(float))
            {
                Console.WriteLine($"【{totalBitCount}】位二进制对应的浮点数为【{destNumber}】,使用BitConverter转换为浮点数的结果为【{BitConverter.ToSingle(binaryArraySource, 0)}】");
                return (T)(object)float.Parse(destNumber);
            }
            else
            {
                Console.WriteLine($"【{totalBitCount}】位二进制对应的浮点数为【{destNumber}】,使用BitConverter转换为浮点数的结果为【{BitConverter.ToDouble(binaryArraySource, 0)}】");
                return (T)(object)double.Parse(destNumber);
            }
        }



        #endregion

    }

    /// <summary>
    /// 十进制转二进制
    /// </summary>
    public class Convert10To2
    {
        /// <summary>
        /// 将十进制的16位整型数转换为16位二进制字符串
        /// </summary>
        /// <param name="i"></param>
        /// <returns></returns>
        public static bool Int16ToBinary(short i, out string v)
        {
            try
            {
                v = Convert.ToString(i, 2).PadLeft(16, '0');
                return true;
            }
            catch (Exception)
            {
                v = default;
                return false;
            }
        }

        /// <summary>
        /// 将十进制的32位整型数转换为32位二进制字符串
        /// </summary>
        /// <param name="i"></param>
        /// <returns></returns>
        public static bool Int32ToBinary(int i, out string v)
        {
            try
            {
                v = Convert.ToString(i, 2).PadLeft(32, '0');
                return true;
            }
            catch (Exception)
            {
                v = default;
                return false;
            }
        }

        /// <summary>
        /// 将十进制的64位整型数转换为64位二进制字符串
        /// </summary>
        /// <param name="i"></param>
        /// <returns></returns>
        public static bool Int64ToBinary(long i, out string v)
        {
            try
            {
                v = Convert.ToString(i, 2).PadLeft(64, '0');
                return true;
            }
            catch (Exception)
            {
                v = default;
                return false;
            }
        }

        /// <summary>
        /// 将十进制的32位单精度浮点数转换为32位二进制字符串
        /// </summary>
        /// <param name="i"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        public static bool Float32ToBinary(float i, out string v)
        {
            try
            {
                float j = i;
                i = Math.Abs(i);
                int i_left = Convert.ToInt32(Math.Floor(i));//获取整数部分
                float i_right = i - i_left;//获取小数部分
                Int32ToBinary(i_left, out string left);//整数部分转换为二进制
                string right = "";
                while (i_right != 1)//小数部分转换为二进制
                {
                    float temp = i_right * 2;
                    right += temp >= 1 ? "1" : "0";
                    if (temp == 1 || temp == 0)
                    {
                        break;
                    }
                    i_right = temp > 1 ? temp - 1 : temp;
                }
                string S = j > 0 ? "0" : "1";//获取符号位的二进制
                if (!left.Contains("1"))
                {
                    int e = 127 - (right.IndexOf('1') + 1);//获取指数位的十进制
                    Int32ToBinary(e, out string E);//获取指数位的二进制
                    string M = right.Substring(right.IndexOf('1') + 1);
                    if (M.Length > 23)
                    {
                        M = M.Substring(0, 23);
                    }
                    else if (M.Length < 23)
                    {
                        M = M.PadRight(23, '0');
                    }
                    v = S + E.Substring(E.Length - 8) + M;
                }
                else
                {
                    int e = left.Length - left.IndexOf('1') - 1 + 127;//获取指数位的十进制
                    Int32ToBinary(e, out string E);//获取指数位的二进制
                    var z = (left.IndexOf('1') + 1);//获取最高正数位
                    string M = ((z >= left.Length ? "" : left.Substring(z)) + right);//获取尾数
                    if (M.Length > 23)
                    {
                        M = M.Substring(0, 23);
                    }
                    else if (M.Length < 23)
                    {
                        M = M.PadRight(23, '0');
                    }
                    v = S + E.Substring(E.Length - 8) + M;
                }
                return true;
            }
            catch (Exception)
            {
                v = default;
                return false;
            }
        }
    }

    /// <summary>
    /// 二进制转十进制
    /// </summary>
    public class Convert2To10
    {
        /// <summary>
        /// 将32位二进制字符串转换为十进制的单精度浮点数
        /// </summary>
        /// <param name="i"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        public static bool BinaryToFloat32(string i, out float v)
        {
            try
            {
                var s = i.Substring(0, 1);//获取符号位字符串
                var e = i.Substring(1, 8);//获取指数位字符串
                var m = i.Substring(9);//获取尾数字符串
                BinaryToInt32(s, out int S);//把符号转换成十进制
                BinaryToInt32(e, out int E);//获取指数转换成十进制
                var m_left = $"1{m.Substring(0, E - 127)}";//获取整数部分二进制字符串
                var m_right = m.Substring(E - 127);//获取小数部分二进制字符串
                BinaryToInt32(m_left, out int left);//把整数部分转换为十进制
                var right = 0f;
                for (int index = 0; index < m_right.Length; index++)//把小数部分转换为十进制
                {
                    var temp_value = Convert.ToSingle(m_right[index].ToString());
                    var temp_index = Convert.ToSingle(Math.Pow(2, -(index + 1)));
                    right += (temp_value * temp_index);
                }
                v = left + right;//合并整数部分和小数部分
                v = S == 1 ? -v : v;//添加符号
                return true;
            }
            catch
            {
                v = default;
                return false;
            }
        }

        public static bool TryTo10(int[] i, out float v)
        {
            string str = string.Join("", i);
            return BinaryToFloat32(str, out v);
        }
        /// <summary>
        /// 将32位二进制字符串转换为十进制的32位整型数
        /// </summary>
        /// <param name="i"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        public static bool BinaryToInt32(string i, out int v)
        {
            try
            {
                v = Convert.ToInt32(i, 2);
                return true;
            }
            catch
            {
                v = default;
                return false;
            }
        }
    }


}
